package util

import (
	"errors"
	"fmt"
	"reflect"
	"runtime"
	"strings"
)

// GetFuncName 取函数全路径名称
func GetFullFuncName(i interface{}) string {
	return runtime.FuncForPC(reflect.ValueOf(i).Pointer()).Name()
}

// GetFuncName 取函数名称
func GetFuncName(i interface{}) string {
	full := GetFullFuncName(i)
	last := strings.LastIndexByte(full, '.')
	if last == -1 {
		return full
	} else {
		return full[last+1:]
	}
}

// SimpleCopyFields 拷贝属性 dst,src 不能为 nil
func SimpleCopyFields(dst, src interface{}) (err error) {
	// 防止意外panic
	defer func() {
		if e := recover(); e != nil {
			err = fmt.Errorf("%v", e)
		}
	}()

	dstType, dstValue := reflect.TypeOf(dst), reflect.ValueOf(dst)
	srcType, srcValue := reflect.TypeOf(src), reflect.ValueOf(src)

	// dst必须结构体指针类型
	if dstType.Kind() != reflect.Ptr || dstType.Elem().Kind() != reflect.Struct {
		return errors.New("dst type should be a struct pointer")
	}

	// src必须为结构体或者结构体指针
	if srcType.Kind() == reflect.Ptr {
		srcType, srcValue = srcType.Elem(), srcValue.Elem()
	}
	if srcType.Kind() != reflect.Struct {
		return errors.New("src type should be a struct or a struct pointer")
	}

	// 取具体内容
	dstType, dstValue = dstType.Elem(), dstValue.Elem()

	// 属性个数
	numField := dstType.NumField()

	for i := 0; i < numField; i++ {
		dstFieldValue := dstValue.Field(i)
		if !dstFieldValue.CanSet() {
			continue
		}
		// 属性
		dstField := dstType.Field(i)

		// 待填充属性值
		srcFieldValue := srcValue.FieldByName(dstField.Name)
		if !srcFieldValue.IsValid() {
			continue
		}

		if dstField.Type == srcFieldValue.Type() {
			dstFieldValue.Set(srcFieldValue)
			continue
		}
		if srcFieldValue.Kind() == reflect.Ptr && !srcFieldValue.IsNil() && srcFieldValue.Type().Elem() == dstField.Type {
			dstFieldValue.Set(srcFieldValue.Elem())
			continue
		}
		if dstFieldValue.Kind() == reflect.Ptr && dstField.Type.Elem() == srcFieldValue.Type() {
			dstFieldValue.Set(reflect.New(srcFieldValue.Type()))
			dstFieldValue.Elem().Set(srcFieldValue)
			continue
		}
	}
	return nil
}
